#include <stdint.h>

#ifndef CLASSFILE_H
#define CLASSFILE_H

#define ACC_PUBLIC     0x0001
#define ACC_PRIVATE    0x0002
#define ACC_PROTECTED  0x0004
#define ACC_STATIC     0x0008
#define ACC_FINAL      0x0010
#define ACC_SUPER      0x0020
#define ACC_VOLATILE   0x0040
#define ACC_BRIDGE     0x0040
#define ACC_TRANSIENT  0x0080
#define ACC_VARARGS    0x0080
#define ACC_NATIVE     0x0100
#define ACC_INTERFACE  0x0200
#define ACC_ABSTRACT   0x0400
#define ACC_STRICT     0x0800
#define ACC_SYNTHETIC  0x1000
#define ACC_ANNOTATION 0x2000
#define ACC_ENUM       0x4000

#define CONSTANT_Class               7
#define CONSTANT_Fieldref            9
#define CONSTANT_Methodref          10
#define CONSTANT_InterfaceMethodref 11
#define CONSTANT_String              8
#define CONSTANT_Integer             3
#define CONSTANT_Float               4
#define CONSTANT_Long                5
#define CONSTANT_Double              6
#define CONSTANT_NameAndType        12
#define CONSTANT_Utf8                1

typedef struct
{
	int nameidx;
	int len;
	char *type;
	void *info;
} attr;

typedef struct
{
	int accflags;
	int nameidx;
	int descidx;
	int attrcnt;
	attr *attrs;
} fld;

typedef struct
{
	int accflags;
	int nameidx;
	int descidx;
	int attrcnt;
	attr *attrs;
} meth;

/************** Attribute types *******************/
/* Straight from JVM spec */

typedef unsigned char u1;
typedef unsigned short u2;
typedef unsigned int u4;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u2 constantvalue_index;
} ConstantValue_attribute;

/* created from the substructure for exception table in code attribute */
typedef struct
{
	u2 start_pc;
	u2 end_pc;
	u2 handler_pc;
	u2 catch_type;
} Code_exception_tbl;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u2 max_stack;
	u2 max_locals;
	u4 code_length;
	u1 *code;
	u2 exception_table_length;
	Code_exception_tbl *exception_table;
	u2 attributes_count;
	attr *attributes;
} Code_attribute;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u2 number_of_exceptions;
	u2 *exception_index_table;
} Exceptions_attribute;

typedef struct
{
	u2 inner_class_info_index;
	u2 outer_class_info_index;
	u2 inner_name_index;
	u2 inner_class_access_flags;
} InnerClass_class;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u2 number_of_classes;
	InnerClass_class *classes;
} InnerClasses_attribute;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
} Synthetic_attribute;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u2 sourcefile_index;
} SourceFile_attribute;

typedef struct
{
	u2 start_pc;
	u2 line_number;
} LineNumberTable_linenumber;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u2 line_number_table_length;
	LineNumberTable_linenumber *line_number_table;
} LineNumberTable_attribute;

typedef struct
{
	u2 start_pc;
	u2 length;
	u2 name_index;
	u2 descriptor_index;
	u2 index;
} LocalVariableTable_localvariable;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u2 local_variable_table_length;
	LocalVariableTable_localvariable *local_variable_table;
} LocalVariableTable_attribute;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
} Deprecated_attribute;

/* new for java 5 */
typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u2 class_index;
	u2 method_index;
} EnclosingMethod_attribute;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u2 signature_index;
} Signature_attribute;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u1 *debug_extension;
} SourceDebugExtension_attribute;

typedef struct
{
	u2 start_pc;
	u2 length;
	u2 name_index;
	u2 signature_index;
	u2 index;
} LocalVariableTypeTable_localvariabletype;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u2 local_variable_type_table_length;
	LocalVariableTypeTable_localvariabletype *local_variable_type_table;
} LocalVariableTypeTable_attribute;

struct Annotations_annotation;

typedef struct Annotations_elementvalue
{
	u1 tag;
	union
	{
		u2 const_value_index;
		struct
		{
			u2 type_name_index;
			u2 const_name_index;
		} enum_const_value;
		u2 class_info_index;
		struct Annotations_annotation *annotation_value;
		struct
		{
			u2 num_values;
			struct Annotations_elementvalue *values;
		} array_value;
	} value;
} Annotations_elementvalue;

typedef struct
{
	u2 element_name_index;
	Annotations_elementvalue value;
} Annotations_elementvaluepair;

typedef struct Annotations_annotation
{
	u2 type_index;
	u2 num_element_value_pairs;
	Annotations_elementvaluepair *element_value_pairs;
} Annotations_annotation;

/*
 * this structure is used to represent:
 * RuntimeVisibleAnnotations_attribute
 * and
 * RuntimeInvisibleAnnotations_attribute
 * and
 * RuntimeVisibleParameterAnnotations_attribute.parameter_annotations
 */
typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u2 num_annotations;
	Annotations_annotation *annotations;
} RuntimeAnnotations_attribute;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	u1 num_parameters;
	RuntimeAnnotations_attribute parameter_annotations;
} RuntimeVisibleParameterAnnotations_attribute;

typedef struct
{
	/*
	u2 attribute_name_index;
	u4 attribute_length;
	*/
	Annotations_elementvalue default_value;
} AnnotationDefault;

/************** constant pool types ********************/

/* ref info, eg. methodref, fieldref, interface methodref, etc */
typedef struct
{
	u1 tag;
	u2 classidx;
	u2 nametypeidx;
} refinfo;

typedef struct
{
	u2 nameidx;
	u2 typeidx;
} nametypeinfo;

/* constant pool entry */
typedef struct cpent
{
	int cpidx;
	char type;
	char isheap;
	union {
		int idx;
		struct {
			int len;
			char *bytes;
		} str;
		void *data;
		int u4int;
		float u4float;
		int64_t u8long;
		double u8double;
	} info;
} cpent;

typedef struct
{
	int magic;
	int version; /* minor << 16 & major, read straight from file */
	int cpcnt;
	cpent *cpool; /* constant pool, linked list */
	int accflags;
	int thiscls;
	int supercls;
	int ifcnt;
	short *ifs;
	int fldcnt;
	fld *flds;
	int methcnt;
	meth *meths;
	int attrcnt;
	attr *attrs;
} jcf; /* java class file */

int jclassfile_read(char *bytes, jcf *cf);

#endif /* CLASSFILE_H */

